﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OWLServer.owl.tipos;

namespace OWLServerQL.dominio
{
    /// <summary>
    /// Elementos base para generar la consulta
    /// </summary>
    public class Elemento
    {
        private bool negado;
        private TipoUnion unionAnterior;
        private Elemento elementoSiguiente;
        private TipoElemento tipoElemento;

        /// <summary>
        /// Tipo de union con el elemento anterior
        /// </summary>
        public TipoUnion UnionAnterior
        {
            get { return unionAnterior; }
            set { unionAnterior = value; }
        }

        /// <summary>
        /// indica si esta negado el elemento o no
        /// </summary>
        public bool Negado
        {
            get { return negado; }
            set { negado = value; }
        }

        /// <summary>
        /// Elemento siguiente a este elemento
        /// </summary>
        public Elemento ElementoSiguiente
        {
            get { return elementoSiguiente; }
            set { elementoSiguiente = value; }
        }

        /// <summary>
        /// Tipo de elemento
        /// </summary>
        public TipoElemento TipoElemento
        {
            get { return tipoElemento; }
            set { tipoElemento = value; }
        }

        public Elemento()
        {
            this.tipoElemento = TipoElemento.NINGUNO;
            this.UnionAnterior = TipoUnion.NINGUNA;
        }

        public Elemento(TipoElemento tipoElemento) : this()
        {
            this.tipoElemento = tipoElemento;
        }

        public Elemento(bool negado)
            : this()
        {
            this.Negado = negado;
        }

        /// <summary>
        /// Comopone la lista de individuos que se están buscando en la consulta
        /// </summary>
        /// <param name="individuosOntologia">Lista de individuos de la Onlología seleccionada</param>
        /// <returns></returns>
        virtual public List<Individuo> owlServerQLToIndividuos(TipoElemento tipoElemento, List<Individuo> individuosOntologia)
        {
            if (TipoElemento == dominio.TipoElemento.NINGUNO)
            {
                TipoElemento = tipoElemento;
            }
            return null;
        }

        /// <summary>
        /// Compone una lista con los individuos comunes de los dos conjuntos
        /// </summary>
        /// <param name="conjuntoIzquierda">Conjunto de individuos izquierdo</param>
        /// <param name="conjuntoDerecha">Conjunto de individuos derecho</param>
        /// <returns>Resultado de la union.</returns>
        protected List<Individuo> unionAndIndividuos(List<Individuo> conjuntoIzquierda, List<Individuo> conjuntoDerecha)
        {
            List<Individuo> resultado = new List<Individuo>();

            foreach (Individuo indiIzq in conjuntoIzquierda) {
                foreach (Individuo indiDer in conjuntoDerecha)
                {
                    if (indiIzq.Equals (indiDer))
                    {
                        if (!resultado.Contains(indiIzq))
                        {
                            resultado.Add(indiIzq);
                        }
                    }
                }
            }

            return resultado;
        }

        /// <summary>
        /// Compone una lista con la unión de los dos conjuntos
        /// </summary>
        /// <param name="conjuntoIzquierda">Conjunto de individuos izquierdo</param>
        /// <param name="conjuntoDerecha">Conjunto de individuos derecho</param>
        /// <returns>Resultado de la union.</returns>
        protected List<Individuo> unionOrIndividuos(List<Individuo> conjuntoIzquierda, List<Individuo> conjuntoDerecha)
        {
            List<Individuo> resultado = new List<Individuo>();

            if (conjuntoIzquierda != null)
            {
                foreach (Individuo indi in conjuntoIzquierda)
                {
                    if (!resultado.Contains(indi))
                    {
                        resultado.Add(indi);
                    }
                }
            }

            if (conjuntoDerecha != null)
            {
                foreach (Individuo indi in conjuntoDerecha)
                {
                    if (!resultado.Contains(indi))
                    {
                        resultado.Add(indi);
                    }
                }
            }

            return resultado;
        }

        /// <summary>
        /// Componemos una lista con los individuos segun la unión de los conjuntos
        /// </summary>
        /// <param name="conjuntoIzquierda">Conjunto de individuos izquierdo</param>
        /// <param name="conjuntoDerecha">Conjunto de individuos derecho</param>
        /// <returns>Resultado de la union.</returns>
        protected List<Individuo> unionIndividuos(List<Individuo> conjuntoIzquierda, List<Individuo> conjuntoDerecha)
        {
            List<Individuo> resultado = new List<Individuo>();

            if (ElementoSiguiente != null)
            {
                switch (ElementoSiguiente.UnionAnterior)
                {
                    case TipoUnion.AND:
                        resultado = unionAndIndividuos(conjuntoIzquierda, conjuntoDerecha);
                        break;
                    case TipoUnion.OR:
                    case TipoUnion.NINGUNA:
                        resultado = unionOrIndividuos(conjuntoIzquierda, conjuntoDerecha);
                        break;
                    default:
                        break;
                }
            }
            else
            {
                resultado = conjuntoIzquierda;
            }

            return resultado;
        }

        /// <summary>
        /// Inserta un individuo en la lista si no esta ya insertado
        /// </summary>
        /// <param name="individuos">Lista de individuos</param>
        /// <param name="individuo">Individuo a insertar</param>
        protected void insertarIndividuo(List<Individuo> individuos, Individuo individuo)
        {
            if (!individuos.Contains(individuo))
            {
                individuos.Add(individuo);
            }
        }
    }
}
